#include "SphereSample.h"
#include "Application.h"
#include "utils.h"
#include <thread>
namespace RayTracer
{
	void SphereSample::Init()
	{
		curIndex = 0;
		isGenerate = false;
		mImageParam = ImageParam(800, 500, "Sphere.png");
		viewport_height = 2.0;
		viewport_width = aspect_ratio * viewport_height;
		focal_length = 1.0;

		horizontal = vec3(viewport_width, 0, 0);
		vertical = vec3(0, viewport_height, 0);
		lower_left_corner = origin - horizontal / 2.0f - vertical / 2.0f - vec3(0, 0, focal_length);

		upColor = vec3(0.5, 0.7, 1.0);
		downColor = vec3(1.0);
		sphereColor = vec3(1.0,0.0,0.0);
	}
	void SphereSample::Render()
	{
		int width = mImageParam.mWidth;
		int height = mImageParam.mHeight;
		uint8_t* pixels = new uint8_t[width * height * 3];
		int index = 0;
		for (int j = height - 1; j >= 0; j--) {
			for (int i = 0; i < width; ++i) {
				auto u = float(i) / (width - 1);
				auto v = float(j) / (height - 1);
				Ray ray(origin, lower_left_corner + u * horizontal + v * vertical - origin);
				vec3 color = RayColor(ray);
				pixels[index++] = static_cast<uint8_t>(255.999f * color.r);
				pixels[index++] = static_cast<uint8_t>(255.999f * color.g);
				pixels[index++] = static_cast<uint8_t>(255.999f * color.b);
				curIndex++;
			}
		}
		Utils::SaveImage(("Images/" + mImageParam.mName).c_str(), width, height, 3, pixels);
		isGenerate = true;
	}
	void SphereSample::ImGui()
	{
		ImGui::Text(u8"Sphere");
		ImGui::Separator();
		ImGui::Text(u8"Sky Color");
		ImGui::ColorEdit3(u8"High", &upColor[0]);
		ImGui::ColorEdit3(u8"Low", &downColor[0]);
		ImGui::Separator();
		ImGui::Text(u8"Sphere");
		ImGui::ColorEdit3(u8"Sphere Color", &sphereColor[0]);
		ImGui::Separator();
		auto w = (float)mImageParam.mWidth;
		auto h = (float)mImageParam.mHeight;
		auto progress = ((float)curIndex / (w * h));
		ImGui::ProgressBar(progress);
		if (ImGui::Button(u8"Generate")) {
			std::thread t = std::thread([=]() { Render(); });
			t.detach();
		}
		if (isGenerate) {
			auto mTexHandle = Utils::LoadTexture(("Images/" + mImageParam.mName).c_str());
			Application::GetInstance()->SetTexHandle(mTexHandle);
			isGenerate = false;
		}
		ImGui::SameLine();
		if (ImGui::Button("Reset")) { Reset(); }

	}
	void SphereSample::ShutDown()
	{
		Application::GetInstance()->SetTexHandle(0);
	}
	vec3 SphereSample::RayColor(const Ray & r)
	{
		if (HitSphere(vec3(0.f,0.f,-1.f), 0.5f, r))
			return sphereColor;
		vec3 unit_direction = glm::normalize(r.direction());
		auto t = 0.5f*(unit_direction.y + 1.0f);
		return (1.0f - t)*downColor + t * upColor;
	}
	bool SphereSample::HitSphere(const vec3 & center, double radius, const Ray & r)
	{
		vec3 oc = r.origin() - center;
		auto a = dot(r.direction(), r.direction());
		auto b = 2.0 * dot(oc, r.direction());
		auto c = dot(oc, oc) - radius * radius;
		auto discriminant = b * b - 4 * a*c;
		return (discriminant > 0);
	}

	void SphereSample::Reset()
	{
		curIndex = 0;
		isGenerate = false;
		upColor = vec3(0.5, 0.7, 1.0);
		downColor = vec3(1.0);
		sphereColor = vec3(1.0, 0.0, 0.0);
		Application::GetInstance()->SetTexHandle(0);
	}
}